#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <curses.h>
#include <netinet/in.h>
#include <netdb.h>
#include <unistd.h>
#include "client.h"
#include <openssl/rsa.h>
#include <openssl/pem.h>
#include <openssl/rand.h>
#include <sys/socket.h>


#define BORRA_BUFFER while (getchar() != '\n')

static int getOption(void)
{
	OptionType option;
	int ret;
	printf("------------------ DEFECT SENDER MENU ----------------------\n");
	do
	{
		printf("------------------ Choose an option ------------------------\n");
		printf("\n1 - Send content from file \n"
				/*"2 - Send content from terminal\n"*/
				"2 - List avaliable file\n"
				/*"3 - Search a file\n"*/
				"4 - Get a file (& set special permission)\n"				
				/*"5 - Set a file permisson\n"*/
				"6 - QUIT\n");
		printf("\nOption: ");
		ret = scanf("%u", &option);
		
		BORRA_BUFFER;
		if(option > OPT_QUIT || option < 1)
			fprintf(stderr, "Invalid option.\n");
		option--;
	}
	while(ret != 1  || option == OPT_LIST_FIL_FILES || (option < OPT_SEND_FILE || option > OPT_QUIT));
	return option;	
}

static int getListOption(void)
{
	OptionType option;
	int ret;
	printf("Get a file / Filter search\n");
	do
	{
		printf("------------------ Choose an option ------------------------\n");
		printf("\n1 - Filter search\n"
				/*"2 - Get a file\n"*/
				"4 - No action\n");
		printf("\nOption: ");
		ret = scanf("%u", &option);
		
		BORRA_BUFFER;
		if(option > OPT_QUIT || option < 1)
			fprintf(stderr, "Invalid option.\n");
		option+=1;
		
	}
	while(ret != 1 || (option != OPT_LIST_FIL_FILES && /*option != OPT_GET_FILE 
		&& */ option != OPT_QUIT));
	return option;	
}

static int getPermOption(void)
{
	OptionType option;
	int ret;
	printf("Set special permission\n");
	do
	{
		printf("----------------- Choose an option ------------------------\n");
		printf("\n1 - Set special permission to a file.\n"
			"2 - No action\n");
		printf("\nOption: ");
		ret = scanf("%u", &option);
		
		BORRA_BUFFER;
		if(option > OPT_QUIT || option < 1)
			fprintf(stderr, "Invalid option.\n");
		option+=3;
		
	}
	while(ret != 1 || (option != OPT_SET_PERMISSION	&& option != OPT_QUIT));
	return option;	
}

static int getSectorOption(ListPacket sectors)
{
	OptionType option;
	int ret,i;
	printf("\nChoose a Sector/Level to set the new file.\n");
	do
	{
		printf("----------------- Choose an option ------------------------\n\n");
		for(i=0; i< sectors.amount; i++)
			printf("%d - %s.\n",i+1,sectors.documents[i]);
		printf("\n\nOption: ");
		ret = scanf("%u", &option);
		
		BORRA_BUFFER;
		
		if(option > sectors.amount  || option < 1)
			fprintf(stderr, "Invalid option.\n");
		
	}
	while(ret != 1 || (option > sectors.amount  || option < 1));
	
	return --option;	
}

static void
loading(char* msg, int usec)
{
	int i;
	printf("Loading %s, please wait",msg);
	fflush(stdout);
	for(i=0;i < 10;i++){
		usleep(usec/10);
		printf(".");
		fflush(stdout);
	}
	printf("\n");
}

static void
getString(char * string, const char * askingFor, int max, int visible)
{
	int i = 0;
	char c;

	printf(askingFor);
		
	while((c = getchar())!='\n')
	{
		if(i == max - 1)
		{
			fprintf(stderr,"WARNING: entered text is too long!\n");
			break;
		}
		string[i++] = c;
	}
	
	string[i]='\0';
	return;
}

//VER QUE ES PARECIDA A COPYFILE
/*static int
getFromFile(char * path, char * info)
{
	int c, i = 0;
	
	FILE * infoFile;
	if((infoFile = fopen(path, "r")) == NULL)
	{
		fprintf(stderr,"File %s does not exists.\n",path);
		return 0; 
	}
		
	while((c=fgetc(infoFile)) != EOF)
	{
		if(i == MAX_INFO)
		{
			fprintf(stderr,"Maximum size reached.\n");
			break;
		}
		info[i++] = c;
	}
	return 1;

}

*/
//VER SI HACE FALTA!!!!
//SOLO LEVANTA ARCH DEL FS
/*
static int getData(int option, char * info, char * path)
{
	int c, i = 0;
	
	switch(option)
	{
		case OPT_SEND_FILE:
			getString(path, "Absolute path to the archive: ", MAX_PATH, 1);
			if(!getFromFile(path, info))
				return 0;
			getFromFile(path, info);
			break;
			
		case OPT_SEND_TERMINAL:
			printf("Enter the file content (When finished, type CTRL + D)\n");
			while((c=getchar())!=EOF)
			{
				if(i == MAX_INFO)
				{
					fprintf(stderr,"Maximum size reached.\n");
					break;
				}
				info[i++] = c;
			}
			getString(path, "Enter the filename for the archive: ", MAX_PATH, 1);
			break;
	}
	return 1;
}
*/

static int doClient(int socket, char * user, char * sessionPassword, char *encryptedPassword)
{
	int option, listopt;
	char * filter ;
	char sessionPwd[MAX_KEY];
	char filename[MAX_PATH];
	
	//printf("**%s**\n", encryptedPassword);
	//fflush(stdout);

	//VERRRR puede ser un while?
	if(true)
	{
		option = getOption();
		if(option == OPT_QUIT) 
		{
			fprintf(stdout,"\nThanks for using DEFECT security program!\n\n\n");
			close(socket);
			return 1;
		}
		
		if(option == OPT_SEND_FILE)
			doSendFile(socket,sessionPassword); //VER Encrypted pass
		
		if(option == OPT_LIST_FILES)
		{
			filter = NULL;
			while(1)
			{
				listopt = doListFiles(socket,  filter); //first search with no filter
				if (listopt == OPT_LIST_FIL_FILES)
				{
					free(filter);//free(NULL) pasa bien!
					if((filter=malloc(MAX_PATH+1))==NULL)
						return -1;
					getString(filter, "Enter filter string: ", MAX_PATH, 1);
			
					if(!strcmp(filter,""))
						filter = NULL; //empty filter
				}
				else
				{
					option = listopt; //for getfile option
					break;
				}
			}
		}		
			
		if(option == OPT_GET_FILE)
			if( doGetFile(socket, user,sessionPassword, encryptedPassword,sessionPwd, filename) == OPT_SET_PERMISSION)
				if( doSetPerm(socket, sessionPwd, filename, encryptedPassword) == -1)
				{
					fprintf(stderr,"Could not set requested permission.\n");
					return -1;
				}
		
		if( option == OPT_SET_PERMISSION)
		{
			fprintf(stderr, "Invalid option\n");
		/*	if( doSetPerm(socket) == -1)
			{
				fprintf(stderr,"Could not set requested permission.\n");
				return -1;
			}*/
		}
	}
	return option;
}

static int 
CopyFile(char * dest, char * filename)
{
	int c,i=0;
	FILE* f;
	
	if((f=fopen(filename,"rb"))==NULL)
		return -1;
	
	while((c=fgetc(f))!=EOF)
	{
		dest[i++]=c;
	}
	
	fclose(f);
	return 1;
}

int
doSendFile(int socket, char * encryptedPassword)/*pass de sesion*/
{
	int sec_num=0,lev_num=0, flag, fsize;
	RequestPacket requester;
	MessagePacket resp;
	ContentPacket fileContent;
	ListPacket list,list2;
	char cryFilename[MAX_TITLE+5];
	
	requester.request = SEND_FILE;
	strcpy(requester.fileName , ""); //NULL: empty field
	
	//server check given the user if belongs to more than one sector
	sendto(socket, &requester, sizeof(requester), 0, NULL, 0);
	
	recvfrom(socket, &resp, sizeof(resp), 0, NULL, 0);
	//printf("\nRecibi ACK: %d\n", resp.response);
	//fflush(stdout);
	//sleep(3);
	
	//printf("\nRecibi ACK: %d\n", resp.response);
	//OK: one sector
	if(resp.response == ACK_OK  || resp.response == ACK_WARNING )
	{
		//set the sector and level
		//belongs to more than one sector 
		if(resp.response == ACK_WARNING)
		{
			recvfrom(socket, &list, sizeof(list), 0, NULL, 0);
			
			sec_num = getSectorOption( list );
			strcpy(fileContent.sector, list.documents[sec_num]);
		
			//send packet
			resp.response = ACK_OK;
			strcpy(resp.message, fileContent.sector);
			sendto(socket, &resp, sizeof(resp), 0, NULL, 0);
		}
		else
			strcpy(fileContent.sector, "");

		recvfrom(socket, &resp, sizeof(resp), 0, NULL, 0);
	//printf("\nRecibi ACK: %d\n", resp.response);
	//fflush(stdout);
	//sleep(3);
			
		//Select the level
		if(resp.response == ACK_WARNING)
		{
			recvfrom(socket, &list2, sizeof(list2), 0, NULL, 0);
			
			lev_num = getSectorOption( list2 );
			
			strcpy(fileContent.level, list2.documents[lev_num]); //server know my level
			
			resp.response=ACK_OK;
			send(socket, &resp,sizeof(resp),0);
		
		}
		else
			strcpy(fileContent.level, ""); //server know my level
		
		/* OJO ACA, SI PERTENECE A UN SOLO SECTOR NO HAY NADA EN list.documents[sec_num]*/
		strcpy(fileContent.sessionDecrypt, "");		
		do
		{
			flag = 0;
			getString(fileContent.fileName, "Enter the file name: ", MAX_PATH, 1);
			FILE*f;
			if((f=fopen(fileContent.fileName,"rb"))==NULL)
			{
				fprintf(stderr, "\nFile: [%s] , does not exist!!\n\n",fileContent.fileName);
				flag = 1;
			}
		}while (flag);
		
		encryptedPassword[16]=0;	
		//printf("encriptando... [%s]\n", encryptedPassword);

		
		if( Twofish_enc(2, 128, fileContent.fileName, encryptedPassword )==-1)
		{
			fprintf(stderr, "\nError opening: [%s], please check the path.\n\n", fileContent.fileName);
			return -1;
		}
		
		sprintf(cryFilename, "%s.cry",fileContent.fileName);
		
		/*The file is bigger than accepted size*/
		if( (fsize=file_size(cryFilename)) > MAX_FILE_SIZE )
		{
			remove(cryFilename);
			fprintf(stderr, "\nYour file: [%s], is to big for this system.\n\n", fileContent.fileName);
			strcpy(fileContent.fileName, "");
			sendto(socket, &fileContent, sizeof(fileContent), 0, NULL, 0);
			return -1;
		}
		
		fileContent.fsize=fsize;
		
		if( CopyFile(fileContent.data, cryFilename) == -1)
			return -1;
		
		//send content
		//printf("archivo: %s - sector: %s\n", fileContent.fileName, fileContent.sector);
		//printf("Esta data mando: %s\n", fileContent.data);
		sendto(socket, &fileContent, sizeof(fileContent), 0, NULL, 0);
		
		//erase evidence!
		remove(cryFilename);
		
		recvfrom(socket, &resp, sizeof(resp), 0, NULL, 0);
	//		printf("\nRecibi ACK: %d\n", resp.response);
	//fflush(stdout);
	//sleep(3);
//file well arrived
		if(resp.response == ACK_OK)
		{
			fprintf(stdout, "Your file: [%s], now is protected by DEFECT system.\n\n", fileContent.fileName );
			return 1;
		}	
		else
			fprintf(stderr, "%s: %s\n", (resp.response == ACK_ERROR)?"ERROR":"WARNING",resp.message);
	}
	else
		fprintf(stderr, "ERROR: %s\n", resp.message);
	
	return -1; //response not ok
}

int
doListFiles(int socket, char * filter)
{
	int i;
	RequestPacket requester;
	MessagePacket resp;
	ListPacket list;
	
	requester.request = LIST_FILES;
	
	if(filter == NULL)
		strcpy(requester.fileName, ""); //if null, no filter
	else
		strcpy(requester.fileName, filter); //if null, no filter

	sendto(socket, &requester, sizeof(requester), 0, NULL, 0);

	recvfrom(socket, &resp, sizeof(resp), 0, NULL, 0);
	
	printf("\n\n");
	loading("Data base information", 2000000);
	//sleep(3);
	//printf("ACK %d .\n\n",resp.response);
	
	if(resp.response == ACK_OK)
	{
		
		sendto(socket, &resp, sizeof(resp), 0, NULL, 0);
		//printf("mando ACK\n");
		recv(socket, &list, sizeof(list), 0);
		printf("Actually there are %d document/s in the DEFECT system.\n\n", list.amount);
		for(i = 0 ; i < list.amount ; i++)
		{
			fprintf(stdout, "%s\n", list.documents[i]);
		}
		printf("\n\n");
		return 1;//getListOption();
	}
	else
		fprintf(stderr, "%s: %s\n", (resp.response == ACK_ERROR)?"ERROR":"WARNING",resp.message);
	
	return -1; //response not ok
	
}

int
doGetFile(int socket, char * user, char* pwd,  char *encryptedPassword ,char* sessionPwd, char *filename)
{
	int i, flag = 0, sec_num=0;
	char path [MAX_PATH];
	RequestPacket requester;
	MessagePacket resp, sec_resp;
	ContentPacket filecont;
	ListPacket list;
	RSA* clientPrivate, * serverPublic;
	FILE* fp;
	char* semiDecrypted, *obtained;
	
	//printf("**%s**\n", encryptedPassword);
	//fflush(stdout);
		
	//ask for the file to get
	do{
		flag =0;
		getString(path, "Enter the filename you're looking for: ",MAX_PATH, 1);
		if(!strcmp(path,""))
		{
			fprintf(stderr,"Empty path, please try again...\n");
			flag = 1;
		}
	}while(flag);
	
	//complete packet and send
	requester.request = GET_FILE;
	strcpy(requester.fileName , path); 
	sendto(socket, &requester, sizeof(requester), 0, NULL, 0);
	
	//wait for the answer
	
	//sleep(3);
	
	recvfrom(socket, &resp, sizeof(resp), 0, NULL, 0);
	//printf("\n\nRESP: %d", resp.response);
	
	printf("\n\n");
	loading("Data base information", 3000000);
	
		
	if(resp.response == ACK_OK || resp.response == ACK_WARNING )
	{
		//belongs to more than one sector 
		if(resp.response == ACK_WARNING)
		{
			recvfrom(socket, &list, sizeof(list), 0, NULL, 0);
			
			sec_num = getSectorOption( list );
		
			//send to the server the selected sector	
			sec_resp.response = ACK_OK;
			strcpy(sec_resp.message, list.documents[sec_num]);
			
			sendto(socket, &sec_resp, sizeof(sec_resp), 0, NULL, 0);
			
			//flush(socket);
			//ACK
			recvfrom(socket, &resp, sizeof(resp), 0, NULL, 0);
		
			if(resp.response==ACK_OK)
				printf("Permission OK\n");
			else{
				fprintf(stderr, "%s: %s\n", (resp.response == ACK_ERROR)?"ERROR":"WARNING",resp.message);
				return -1;
			}
			

			//ACK
		}
		
		/* Decrypt pk */
		//get my private key

		//printf("PASS: %s\n",encryptedPassword);
		//printf("PASS: %s\n",encryptedPassword);
		//printf("PASS: %s\n",encryptedPassword);
		//fflush(stdout);

		//printf("PASS: %s\n",encryptedPassword);
		//fflush(stdout);

		if((clientPrivate = privateK_dec(encryptedPassword))==NULL)
		{
			fprintf(stderr, "Error decrypting private key.\n");
			return -1;
		}
		
		//get server public key
		if((fp=fopen("serverPublic.key", "rb"))==NULL)
		{
			fprintf(stderr,"Check you hace Server's public key. See the README file\n");
			return -1;
		}
		
		serverPublic = RSA_new();
			
		if(!PEM_read_RSAPublicKey(fp, &serverPublic, NULL, NULL))
		{
			fprintf(stderr,"Problem in opening server's public key");
			return -1;
		}
		fclose(fp);
		
		//receive the file with the related data 
		recvfrom(socket, &filecont, sizeof(filecont), 0, NULL, 0);
		//sleep(2);
		printf("FN: %s FS:%d SEC: %s LEV %s\n",filecont.fileName,filecont.fsize,filecont.sector,filecont.level);
		
		if ((semiDecrypted = publicDecrypt(filecont.sessionDecrypt, serverPublic)) == NULL)
		{
			printf("Error decrypting with Server public key.\n");
			return -1;
		}
		if ((obtained = privateDecrypt(semiDecrypted, clientPrivate) ) == NULL)
		{
			printf("Error decrypting with client private key.\n");
			return -1;
		}
		
		char newobtained[17];
		memset(newobtained,0,17);
		memcpy(newobtained,obtained,16);
		
		//printf("desencriptando... [%s]\n", newobtained);
	
		
		//obtained=malloc(20);	
		//strcpy(obtained,"ABCDEFGHIJKLMNOP");
		
		//printf("desencriptando... %s\n", encryptedPassword);
		//printf("SESSIONNN obtenida!!!!  [%s]\n",obtained);	
	
		//open a file to decript
		FILE * recfile;
		if( ( recfile = fopen("tmp.cry","wb") ) == NULL )
		{
			fprintf(stderr,"Error while openning file.\n");
			return -1;	
		}	
				
		//complete the file with arrived data
		for(i = 0 ; i<filecont.fsize ; i++)
		{
			fputc(filecont.data[i], recfile);
		}
		fclose(recfile);
		
				
		//decript the file
		if(Twofish_dec(2, 128, "tmp.cry", newobtained)==-1)/*MODE_CBC*/
		{
			fprintf(stderr,"Error while getting file.\n");
			return -1;	
		}	
		//show the file to the user
		//print properties
		if( ( recfile = fopen("tmp.new","rb") ) == NULL )
		{
			fprintf(stderr,"Error while openning file.\n");
			return -1;	
		}
		fprintf(stdout, "FILE: %s\nSECTOR:%s\nLEVEL:%s\nFILE:\n\n",
				filecont.fileName,filecont.sector,filecont.level);

		while((i=fgetc(recfile))!=EOF)
		{
			fprintf(stdout, "%c", i);
		}
		
		//destroy the file
		fclose(recfile);
		remove("tmp.new");
		remove("tmp.cry");
		
		fprintf(stdout, "\n<<EOF>>\n\n");
		
		strcpy(sessionPwd, obtained);
		strcpy(filename, filecont.fileName);
		
		//ask for new permision
		return getPermOption();
	}
	else
		fprintf(stderr, "%s: %s\n", (resp.response == ACK_ERROR)?"ERROR":"WARNING",resp.message);
	
	return -1; //response not ok
}

int doSetPerm(int socket, char* sessionPwd, char *filename,  char *encryptedPassword)
{
	//int sec_num;
	RequestPacket req;
	//Setear permisos a un solo usuario sobre un archivo
	PermPacket reqPerm;
	MessagePacket resp/*, sec_resp*/;
	//ListPacket list;
	RSA * clientPrivate, * serverPublic;
	FILE*fp;
	char * semiEncrypted, * obtained;
	
	
	req.request = SET_PERMISSION;
	sendto(socket, &req, sizeof(req), 0, NULL, 0);
	
	recvfrom(socket, &resp, sizeof(resp), 0, NULL, 0);
	
	if(resp.response == ACK_ERROR || resp.response == ACK_WARNING )
	{
		fprintf(stderr, "%s: %s\n", (resp.response == ACK_ERROR)?"ERROR":"WARNING",resp.message);
		return -1; //response not ok
	}		
		
	reqPerm.request = SET_PERMISSION;
	//getString(reqPerm.fileName, "Enter the filename to increase permission: ",MAX_PATH, 1);
	getString(reqPerm.alloweduser, "Enter the user to give permission: ",MAX_PATH, 1);
	strcpy(reqPerm.fileName,filename);
	strcpy(reqPerm.user,"");
	
	serverPublic = RSA_new();
	
	/* Decrypt pk */
	if((clientPrivate = privateK_dec(encryptedPassword))==NULL)
	{
		fprintf(stderr, "Error decrypting private key.\n");
		return -1;
	}
	if((fp=fopen("serverPublic.key", "rb"))==NULL)
	{
		fprintf(stderr,"Check you hace Server's public key. See the README file\n");
		return -1;
	}
	if(!PEM_read_RSAPublicKey(fp, &serverPublic, NULL, NULL))
	{
		fprintf(stderr,"Problem in opening server's public key");
		return -1;
	}
	fclose(fp);
		
	if ((semiEncrypted = publicEncrypt(sessionPwd, serverPublic)) == NULL)
			printf("Error.PrD");
	
	if ((obtained = privateEncrypt((unsigned char*)semiEncrypted, clientPrivate) ) == NULL)
			printf("errorPuD");
		
	memcpy(reqPerm.sessionKey, obtained, MAX_RSA_SESSION);
		
	printf("\nMANDO\n");
	sendto(socket, &reqPerm, sizeof(reqPerm), 0, NULL, 0);
	printf("\nMANDEEE\n");
	fflush(stdout);
	
	loading("",1000000);
	
	recvfrom(socket, &resp, sizeof(resp), 0, NULL, 0);
	printf("**me llega: %d**\n",resp.response);
	sleep(1);
	if(resp.response == ACK_OK )//|| resp.response == ACK_WARNING )
	{
		//belongs to more than one sector 
		/*if(resp.response == ACK_WARNING)
		{
			recvfrom(socket, &list, sizeof(list), 0, NULL, 0);
			
			sec_num = getSectorOption( list );
		
			//send to the server the selected sector	
			sec_resp.response = ACK_OK;
			strcpy(sec_resp.message, list.documents[sec_num]);
		
			sendto(socket, &sec_resp, sizeof(sec_resp), 0, NULL, 0);
		}
	*/
		//if OK permission conceded
		fprintf(stdout, "Now, user: %s, has permission over: %s\n\n",reqPerm.alloweduser, reqPerm.fileName );
		return 1;
	}	
	else
		fprintf(stderr, "%s: %s\n", (resp.response == ACK_ERROR)?"ERROR":"WARNING",resp.message);
	
	return -1; //response not ok
}

int
getConnected(char * host, char * port, int * descriptor)
{
	struct hostent * hostPtr;
	struct servent * servicePtr;
	
	struct sockaddr_in sin;
	int resp;
	
	
	sin.sin_family = AF_INET;
		
	if((hostPtr = (struct hostent *) gethostbyname(host)) == NULL)
	{
		fprintf(stderr,"Could not resolv name for < %s >, try later...", host);
		return -1;
	}

	memcpy( &(sin.sin_addr), hostPtr->h_addr, hostPtr->h_length);
	
	if((servicePtr = (struct servent *) getservbyname(port, "tcp")) == NULL)
		if((sin.sin_port=htons((unsigned short)atoi(port)))==0)
			return -1;
	
	if( (*descriptor = socket(AF_INET, SOCK_STREAM, 0)) < 0 )
		return -1; /* Socket creation error */
	//connect(*socket );
	
	resp = connect(*descriptor,(struct sockaddr*)&sin,sizeof(sin));
	
	if( resp )
		fprintf(stderr,"Could not connect to < %s >, try later...\n", host);
	else
		printf("Connected to < %s >\n", host);
	return (resp == 0);
}
static int
makeSessionKey(char * buff)
{
	if (RAND_bytes((unsigned char*)buff, MAX_SESSION) == 0)
		return -1;
	return 1;
}
	

int genSessionKey(int socket, AuthPacket authenticate, char * sessionPwd,char * encryptPassword)
{
	RSA * clientPrivate, * serverPublic;
	char buff[MAX_SESSION], * semiEncrypted, * obtained;
	FILE * fp;
	int flag;
	char *pwd;
	
	if(makeSessionKey(buff) == -1)
		return -1;
		
		
	/*printf("SESSIONNN\n");	
	int i =0;
	while(i<16)
		printf("%02X ",buff[i++]);
	printf("\n");
	*/
	//Twofish_enc(2,128, "termo", buff);
	
	//strncpy(buff,"ABCDEFGHIJKLMNOP",MAX_SESSION);
	memcpy(sessionPwd, buff,MAX_SESSION );
	sessionPwd[MAX_SESSION]=0;
	//printf("SESSIONNN obtenida!!!!  [%s]\n",buff);
	
	serverPublic = RSA_new();
	
	do
	{
		flag = 0;
		pwd = getpass("Private Key Password: ");
		if(pwd == NULL || (strlen(pwd) < 4 || strlen(pwd) > 16))
		{
			flag = 1;
			fprintf(stderr,"Your password length is incorrect\nPlease enter a password between 4 and 16 characters\n");
		}
	}		
	while(flag);
	
	/* Decrypt pk */
	if((clientPrivate = privateK_dec(pwd))==NULL)
	{
		fprintf(stderr, "Error decrypting private key.\n");
		return -1;
	}
	
	if((fp=fopen("serverPublic.key", "rb"))==NULL)
	{
		fprintf(stderr,"Check you hace Server's public key. See the README file\n");
		return -1;
	}
	if(!PEM_read_RSAPublicKey(fp, &serverPublic, NULL, NULL))
	{
		fprintf(stderr,"Problem in opening server's public key");
		return -1;
	}
	fclose(fp);
		
	
	if ((semiEncrypted = publicEncrypt(buff, serverPublic)) == NULL)
			printf("Error.PrD");
	
	if ((obtained = privateEncrypt((unsigned char*)semiEncrypted, clientPrivate) ) == NULL)
			printf("errorPuD");
		
	memcpy(authenticate.sessionKey, obtained, MAX_RSA_SESSION);
	
	if ((semiEncrypted = publicEncrypt(authenticate.password, serverPublic)) == NULL)
			printf("Error.PrD");
		
	if ((obtained = privateEncrypt((unsigned char*)semiEncrypted, clientPrivate) ) == NULL)
			printf("errorPuD");
	
	memcpy(authenticate.password, obtained, MAX_RSA_SESSION);
	
	send(socket, &authenticate, sizeof(authenticate), 0);
	
	strcpy(encryptPassword, pwd);
	
	
	return 1;
}

int getAuthenticated(int socket, AuthPacket authenticate)
{
	struct timeval tv;
	MessagePacket resp;
	fd_set rfds;
	
	tv.tv_sec = 2;
	tv.tv_usec = 0;
	FD_ZERO(&rfds);
	FD_SET(socket,&rfds);

	//send(socket, &authenticate, sizeof(authenticate), 0);

	recv(socket, &resp, sizeof(resp), 0);

	if(resp.response == ACK_OK)
	{
		//if OK permission conceded
		fprintf(stdout, "User: %s, is connected!\n\n",authenticate.user);
	}	
	else
	{
		fprintf(stderr, "---->%s: %s\n", (resp.response == ACK_ERROR)?"ERROR":"WARNING",resp.message);
		return -1;
	}
	return 1; 
}

int main(int argc, char ** argv)
{
	char  encryptedPassword[16+1];
	char  sessionKey[16];
	int socket;
	AuthPacket authenticate;
	if(argc != 3)
	{
		fprintf(stderr, "Usage: defect_send <IP_ADDRESS> <PORT>\n");
		return 1;
	}
	
	getString(authenticate.user, "Username: ", MAX_USER, 1);
	strncpy(authenticate.password, getpass("Password: "), MAX_PASS);
	
	if(getConnected(argv[1], argv[2], &socket)==-1)
		return -1;
		
	if(genSessionKey(socket,authenticate, sessionKey, encryptedPassword)==-1)
		return -1;
		
	//printf("sess: %s\n",sessionKey);
	//printf("enc: %s\n",encryptedPassword);
	
	
	loading("", 1000000);
	//*sleep(1);
	
	if(getAuthenticated(socket, authenticate) == -1 )
		return -1;
	
	//printf("**%s**\n", encryptedPassword);
	//fflush(stdout);
	doClient(socket, authenticate.user, sessionKey, encryptedPassword);
	
	return 0;
}

